package com.gsbelarus.gedemin.lib.ui.activity;

import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

import com.afollestad.materialdialogs.GravityEnum;
import com.gsbelarus.gedemin.lib.R;
import com.gsbelarus.gedemin.lib.sync.protocol.SyncProtocolServiceModel;
import com.gsbelarus.gedemin.lib.ui.ArgumentsHelper;
import com.gsbelarus.gedemin.lib.ui.dialog.DialogHelper;

abstract public class SyncActivityModel extends ActionBarActivity {

    protected Context context;
    protected ArgumentsHelper argumentsHelper;
    private BroadcastReceiver br;
    protected FragmentManager fragmentManager;
    private AlertDialog demoDBDialog;
    protected Toolbar toolbar;

    protected ActionBarDrawerToggle mDrawerToggle;

    protected boolean isActivityVisible;
    private boolean isShowingSyncStatusDialog = false;

    private int contentPaddingTop;

    /**
     * @return id View для отрисовки в активити
     */
    abstract public int getViewId();

    /**
     * сделать что-то после успешного или неуспешного обновления БД
     */
    abstract public void onFinishUpdateDB();

    /**
     * сделать что-то когда обновление БД только началось
     */
    public void onStartUpdateDB() {

    }

    /**
     * вызывается в методе onCreate(Bundle)
     *
     * @param arguments bundle с агрументами
     */
    public void onCreateActivity(Bundle arguments) {

    }

    /**
     * setText для заголовка вызыватся в onCreate
     *
     * @return текст заголовка activity
     */
    public String getTitleString() {
        return null;
    }

    /**
     * Если необходимо убрать toolbar, метод переопределяется в классе наследнике и возвращает false
     *
     * @return по умолчанию возвращает true
     */
    protected boolean isShowingToolbar() {
        return true;
    }

    @Override
    final protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actvt);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

        FrameLayout activityContent = (FrameLayout) findViewById(R.id.activity_content);
        activityContent.addView(getLayoutInflater().inflate(getViewId(), activityContent, false), 0);
        contentPaddingTop = activityContent.getPaddingTop();

        showToolbar(activityContent);

        context = getBaseContext();
        fragmentManager = getSupportFragmentManager();
        argumentsHelper = new ArgumentsHelper();

        /** активность может запускать из других экранов или
         * восстанавливаться, если она была перед этим уничтожена ОС в случае нехватки памяти.
         * В первом случае берем данные из Intent,
         * во втором - сохраненные параметры из savedInstanceState */
        if (savedInstanceState == null) {
            argumentsHelper.readParams(getIntent());
        } else
            argumentsHelper.readParams(savedInstanceState);

        if (getSupportActionBar() != null && getTitleString() != null)
            getSupportActionBar().setTitle(getTitleString());

        onCreateActivity(argumentsHelper.saveParams((savedInstanceState == null) ? new Bundle() : savedInstanceState));

        createBroadcastReceiver();
    }

    private void showToolbar(FrameLayout containerForShadow) {
        if (!isShowingToolbar()) {
            showContentPaddingTop(false);
            return;
        }

        FrameLayout actvt = (FrameLayout) findViewById(R.id.actvt);
        toolbar = (Toolbar) getLayoutInflater().inflate(R.layout.toolbar, actvt, false);
        actvt.addView(toolbar);
        findViewById(R.id.actvt_fits_system_windows).setFitsSystemWindows(true);

        setSupportActionBar(toolbar);

        View shadow = getLayoutInflater().inflate(R.layout.drop_shadow, containerForShadow, false);
        containerForShadow.addView(shadow);

        showElevationToolbar(true);
        showContentPaddingTop(true);
    }

    /**
     * Показать/скрыть тень от toolbar.
     * Для API < 21 используется view(drop_shadow) поверх контента
     * Для API >= 21 используется elevation на 10dp
     *
     * @param flag показывать или не показывать
     */
    public void showElevationToolbar(boolean flag) {
        View shadow = findViewById(R.id.drop_shadow);
        if (Build.VERSION.SDK_INT < 21) {
            if (shadow != null)
                shadow.setVisibility((flag) ? View.VISIBLE : View.GONE);

        } else {
            if (shadow != null)
                shadow.setVisibility(View.GONE);
            Toolbar toolbar = getToolbar();
            if (toolbar != null)
                toolbar.setElevation((flag) ? 10 * getResources().getDisplayMetrics().density : 0);
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (mDrawerToggle != null)
            mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        if (mDrawerToggle != null)
            mDrawerToggle.syncState();
    }

    /**
     * ловит и обрабатывает широковещательные сообщения от сервиса обновлений
     */
    private void createBroadcastReceiver() {
        br = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                int status = intent.getIntExtra(SyncProtocolServiceModel.STATUS_SYNC, SyncProtocolServiceModel.NO_SYNC);
                String error = intent.getStringExtra(SyncProtocolServiceModel.ERROR_SYNC);

                /** если сервис синхронизации начал работу */
                if (status == SyncProtocolServiceModel.DO_SYNC) {
                    onStartUpdateDB();
                    if (demoDBDialog != null)
                        demoDBDialog.cancel();
                }

                /** если сервис синхронизации отработал */
                if (status == SyncProtocolServiceModel.NO_SYNC) {

                    /** если сервис синхронизации отработал с ошибкой */
                    if (error != null) {

                        /** если ошибка - Нет интернет соединения, то выходим из метода и не перерисовываем интерфейс */
                        if (error.equals(context.getString(R.string.notification_text_error_inernet))) {
                            showErrorDialog(error);
                            return;
                        }

                        /** перерисовываем интерфейс. переопределяется в классе наследнике */
                        onFinishUpdateDB();

                        /** если флаг для показа ошибок включен */
                        if (isShowingSyncStatusDialog) {

                            /** если уведомление о создании Демо данных*/
//                            if (error.equals(SyncProtocolServiceModel.SUCCESS_CREATE_DEMO)) {
//                                showDemoDialog();
//                                return;
//                            }
                            if (error.equals(getString(R.string.first_launch_text))) {
                                showDemoDialog();
                                return;
                            }

                            /** выводим сообщение об ошибке */
                            showErrorDialog(error);
                        }

                    } else {
                        /** перерисовываем интерфейс. переопределяется в классе наследнике */
                        onFinishUpdateDB();
                    }
                }
            }
        };
        IntentFilter intFilt = new IntentFilter(SyncProtocolServiceModel.getBroadcastMessageAction(getApplicationContext()));
        registerReceiver(br, intFilt);
    }

    private void showErrorDialog(String error) {
        /** если активити не видна, ничего не показываем */
        if (!isActivityVisible) return;
        DialogHelper dialogHelper = new DialogHelper(SyncActivityModel.this);
        demoDBDialog = dialogHelper.showMaterialDialog(getString(R.string.notification_text), error, null);
    }

    private void showDemoDialog() {
        if (!isActivityVisible) return;
        DialogHelper dialogHelper = new DialogHelper(SyncActivityModel.this);
        demoDBDialog = dialogHelper.showMaterialDialog(null, getResources().getString(R.string.first_launch_text), GravityEnum.CENTER);
    }

    @Override
    protected void onPause() {
        super.onPause();
        setActivityVisible(false);
    }

    @Override
    protected void onResume() {
        super.onResume();
        setActivityVisible(true);
    }

    private void setActivityVisible(boolean flag) {
        isActivityVisible = flag;
        SyncProtocolServiceModel.isShowNotificationError = !flag;
    }

    protected boolean isShowingSyncStatusDialog() {
        return isShowingSyncStatusDialog;
    }

    protected void setShowingSyncStatusDialog(boolean isShowingSyncStatusDialog) {
        this.isShowingSyncStatusDialog = isShowingSyncStatusDialog;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (demoDBDialog != null)
            demoDBDialog.cancel();
        unregisterReceiver(br);
    }

    /**
     * сохранение параметров, если процесс вдруг завершиться
     * при нехватке памяти или в каком-нибудь другом случае
     */
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        argumentsHelper.saveParams(outState);
    }

    public void showContentPaddingTop(boolean flag) {
        FrameLayout content = (FrameLayout) findViewById(R.id.activity_content);
        if (content != null) {
            content.setPadding(
                    content.getPaddingLeft(),
                    flag ? contentPaddingTop : 0,
                    content.getPaddingRight(),
                    content.getPaddingBottom());
            content.invalidate();
        }
    }

    protected void setDrawerToggle(ActionBarDrawerToggle mDrawerToggle) {
        this.mDrawerToggle = mDrawerToggle;
    }

    public ActionBarDrawerToggle getDrawerToggle() {
        return mDrawerToggle;
    }

    public Toolbar getToolbar() {
        return toolbar;
    }
}